﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpGL;
using System.Threading;

namespace bitzhuwei.FeedingFrenzy.WorldModel
{
    public class GameWorld : List<GameObject>
    {
        public GameWorld(IGraphics graphicsHolder)
        {
            // TODO: Complete member initialization
            this.graphicsHolder = graphicsHolder;
            this.timer = new System.Windows.Forms.Timer();
            this.timer.Interval = 100;
            this.timer.Tick += new EventHandler(timer_Tick);
        }

        private ulong logicTick;
        private void GameLogic()
        {
            while (this.thrGameLogic != null)
            {
                if (this.logicTick > 0)
                {
                    GetInput();
                    this.Update();
                    this.logicTick--;
                    if (this.logicTick == 0)
                    {
                        this.graphicsHolder.PictureUpdated = true;
                    }
                    else
                    {
                        this.graphicsHolder.PictureUpdated = false;
                    }
                }
                Thread.Sleep(0);
            }
        }


        private void GetInput()
        {
            //throw new NotImplementedException();
        }

        private Thread thrGameLogic;
        private float rotation;
        private IGraphics graphicsHolder;
        private System.Windows.Forms.Timer timer;


        public new void Add(GameObject item)
        {
            if (item != null)
            {
                base.Add(item);
                item.World = this;
            }
        }

        public new void AddRange(IEnumerable<GameObject> collection)
        {
            if (collection == null) return;
            foreach (var item in collection)
            {
                item.World = this;
            }
            base.AddRange(collection);
        }

        public new void Remove(GameObject item)
        {
            var index = this.IndexOf(item);
            if (index >= 0)
            {
                var obj = base[index];
                base.RemoveAt(index);
                obj.World = null;
            }
            //// 若override掉GameObject.Equals的方式不正确，下面的形式就可能出错了。
            //// 被置为null的就不是被Remove掉的那个对象的World了。
            //if (base.Remove(item))
            //{
            //    item.World = null;
            //}
        }

        /// <summary>
        /// Update every object's state
        /// </summary>
        ///// <param name="elapsedTime">elasped time from last update</param>
        public void Update()
        {
            for (int i = 0; i < this.Count; i++)
            {
                var obj = this[i];
                if (obj.AutoMove)
                    obj.Update();
            }

            this.rotation += 10f;
        }

        /// <summary>
        /// Draw every object with opengl
        /// </summary>
        public void Draw()
        {
            var gl = this.graphicsHolder.GetDrawingControl().OpenGL;
            for (int i = 0; i < this.Count; i++)
            {
                var obj = this[i];
                obj.Draw(gl);
            }

            //////  Clear the color and depth buffer.
            ////gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);

            ////  Load the identity matrix.
            //gl.LoadIdentity();

            ////  Rotate around the Y axis.
            //gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);

            ////  Draw a coloured pyramid.
            //gl.Begin(OpenGL.GL_TRIANGLES);
            //gl.Color(1.0f, 0.0f, 0.0f);
            //gl.Vertex(0.0f, 1.0f, 0.0f);
            //gl.Color(0.0f, 1.0f, 0.0f);
            //gl.Vertex(-1.0f, -1.0f, 1.0f);
            //gl.Color(0.0f, 0.0f, 1.0f);
            //gl.Vertex(1.0f, -1.0f, 1.0f);
            //gl.Color(1.0f, 0.0f, 0.0f);
            //gl.Vertex(0.0f, 1.0f, 0.0f);
            //gl.Color(0.0f, 0.0f, 1.0f);
            //gl.Vertex(1.0f, -1.0f, 1.0f);
            //gl.Color(0.0f, 1.0f, 0.0f);
            //gl.Vertex(1.0f, -1.0f, -1.0f);
            //gl.Color(1.0f, 0.0f, 0.0f);
            //gl.Vertex(0.0f, 1.0f, 0.0f);
            //gl.Color(0.0f, 1.0f, 0.0f);
            //gl.Vertex(1.0f, -1.0f, -1.0f);
            //gl.Color(0.0f, 0.0f, 1.0f);
            //gl.Vertex(-1.0f, -1.0f, -1.0f);
            //gl.Color(1.0f, 0.0f, 0.0f);
            //gl.Vertex(0.0f, 1.0f, 0.0f);
            //gl.Color(0.0f, 0.0f, 1.0f);
            //gl.Vertex(-1.0f, -1.0f, -1.0f);
            //gl.Color(0.0f, 1.0f, 0.0f);
            //gl.Vertex(-1.0f, -1.0f, 1.0f);
            //gl.End();

            ////  Load the identity matrix.
            //gl.LoadIdentity();
            //gl.Begin(SharpGL.Enumerations.BeginMode.Lines);
            //gl.Color(1f, 0, 0);
            //gl.Vertex(0, 0, 0);
            //gl.Vertex(this.MaxScope.X, 0, 0);
            //gl.Color(0, 1f, 0);
            //gl.Vertex(0, 0, 0);
            //gl.Vertex(0, this.MaxScope.Y, 0);
            //gl.Color(0, 0, 1f);
            //gl.Vertex(0, 0, 0);
            //gl.Vertex(0, 0, this.MaxScope.Z);
            //gl.End();
            //////  Nudge the rotation.
            ////rotation += 3.0f;
        }

        private TriTuple<int> _maxScope = new TriTuple<int>(10, 2, 10);

        public TriTuple<int> MaxScope
        {
            get { return _maxScope; }
            set { _maxScope = value; }
        }
        private TriTuple<int> _minScope = new TriTuple<int>(-10, 0, -10);

        public TriTuple<int> MinScope
        {
            get { return _minScope; }
            set { _minScope = value; }
        }

        public void Start()
        {
            var gl = this.graphicsHolder.GetDrawingControl().OpenGL;
            gl.ShadeModel(OpenGL.GL_SMOOTH);						// Enables Smooth Shading
            //gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);					// Black Background
            //gl.ClearDepth(1.0f);							// Depth Buffer Setup
            gl.Disable(OpenGL.GL_DEPTH_TEST);						// Disables Depth Testing
            gl.Enable(OpenGL.GL_BLEND);							// Enable Blending
            gl.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE);					// Type Of Blending To Perform
            //gl.Hint(OpenGL.GL_PERSPECTIVE_CORRECTION_HINT, OpenGL.GL_NICEST);			// Really Nice Perspective Calculations
            //gl.Hint(OpenGL.GL_POINT_SMOOTH_HINT, OpenGL.GL_NICEST);					// Really Nice Point Smoothing
            gl.Enable(OpenGL.GL_TEXTURE_2D);						// Enable Texture Mapping

            this.logicTick = 0;
            this.thrGameLogic = new Thread(GameLogic);
            this.thrGameLogic.Priority = ThreadPriority.Highest;
            this.thrGameLogic.Start();
            this.thrGameLogic.IsBackground = true;
            this.timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            this.logicTick++;
        }

        public bool IsRunning()
        {
            return (this.thrGameLogic != null && this.thrGameLogic.IsAlive);
        }

        public void Stop()
        {
            this.thrGameLogic = null;
            this.timer.Stop();
        }

        public override string ToString()
        {
            var builder = new StringBuilder();
            builder.AppendFormat("{0} object(s).", this.Count);
            builder.AppendLine();
            foreach (var item in this)
            {
                builder.AppendLine(item.ToString());
            }
            return builder.ToString();
            //return base.ToString();
        }
    }
}
